<template>
  <div class="container-wrapper" :style="{ height }">
    <div :style="{ height }">
      <canvas resize ref="canvas">
        <slot>
          <m-image-marker-annotations :data="annotations" :selected="selected"></m-image-marker-annotations>
          <m-image-marker-remarks></m-image-marker-remarks>
        </slot>
      </canvas>
    </div>
  </div>
</template>

<script>
import Paper from 'paper'

import BaseConfig, { ReferDirect } from '@/views/mark/meditor/config'
import { Cursor } from './tools/const.js'
import MImageMarkerAnnotations from './MImageMarkerAnnotations'
import MImageMarkerRemarks from './MImageMarkerRemarks'

export default {
  name: 'MImageMarkerView',
  components: { MImageMarkerAnnotations, MImageMarkerRemarks },

  props: {
    height: { type: String, default: '100%' },
    file: { required: true },
    annotations: { type: Array },
  },

  inject: ['getConfig', 'mImageMarker'],
  provide() {
    return {
      getProject: this.getProject,
    }
  },
  computed: {
    config() {
      return this.getConfig()
    },

    selected() {
      return this.mImageMarker.selected
    },
  },

  data() {
    // 非响应变量
    /**
      project: null,
      raster: null,
      rasterLayer: null,
      mainLayer: null,
     */

    return {
      zoom: {
        factor: 1.25,
        maxZoom: 10,
        minZoom: 0.6,
      },
      fontSize: 24,
      attributesTextOpacity: 1,
    }
  },

  created() {},

  mounted() {
    console.log('Image Annotation Item loaded')
    this.initPaperjs()
    window.addEventListener('resize', this.resizeCanvasWithImage, false)
  },

  methods: {
    getProject(callback) {
      const vm = this
      // check for image load
      const checkForProject = () => {
        if (vm.loaded) {
          callback(vm.project)
        } else {
          setTimeout(checkForProject, 50)
        }
      }
      checkForProject()
    },

    initPaperjs() {
      const canvas = this.$refs.canvas
      const { offsetWidth: width, offsetHeight: height } = canvas
      this.viewSize = { width, height }

      // 初始化
      const project = new Paper.Project(canvas)
      project.name = 'project'
      project.view.viewSize = new Paper.Size(width, height)
      project.view.onMouseDrag = this.handlerMouseDrag.bind(this)
      project.view.onMouseUp = this.handlerMouseUp.bind(this)
      project.view.onMouseDown = this.handlerMouseDown.bind(this)
      // project.view.onMouseMove = (event) => {}
      // project.view.onDoubleClick = () => console.log('double click')

      // 自定义事件
      project.updateProperty = this.mImageMarker.updateProperty
      project.onAnnoChange = this.handleAnnotationChange.bind(this)
      project.onSelectedChange = this.handleSelectedChange.bind(this)

      const imageElement = new Image()
      imageElement.onload = this.onImageLoad.bind(this)

      //  bind event listener
      const element = project.view.element
      element.onwheel = this.handleZoom.bind(this)
      element.onmouseenter = (event) => project.activate()
      element.onmouseleave = (event) => {
        // project.deselectAll()
        // console.log(event)
      }

      this.project = project
      this.imageElement = imageElement
      this.view = project.view
    },

    onImageLoad() {
      console.log('The image has finished loading.')
      const { imageElement, project } = this
      const { width: iWidth, height: iHeight } = imageElement
      this.imageSize = { iWidth, iHeight }

      // project.view.viewSize = new Paper.Size(width, height)
      const rasterLayer = new Paper.Layer({ name: 'rasterLayer' })
      rasterLayer.applyMatrix = false
      rasterLayer.activate()

      const raster = new Paper.Raster(imageElement)
      raster.visible = true
      raster.position = new Paper.Point(iWidth * 0.5, iHeight * 0.5)

      const mainLayer = new Paper.Layer({ name: 'mainLayer', children: [rasterLayer] })
      mainLayer.rasterLayer = rasterLayer

      this.mainLayer = mainLayer
      this.rasterLayer = rasterLayer
      this.raster = raster

      this.drwaReferLiens()
      this.drawAnnotation()
      this.resizeCanvasWithImage()
      this.loaded = true
    },

    // 缩放绘图组件
    handleZoom(event) {
      const mousePos = new Paper.Point(event.offsetX, event.offsetY)
      const delta = event.deltaY
      try {
        const { zoom, viewSize, view, project } = this
        const projectPos = view.viewToProject(mousePos)
        const newZoom =
          delta < 0 ? Math.min(view.zoom * zoom.factor, zoom.maxZoom) : Math.max(view.zoom / zoom.factor, zoom.minZoom)

        if (newZoom === view.zoom) return
        const scale = newZoom / view.zoom,
          scaleReverse = view.zoom / newZoom

        // scale font size
        for (const item of project.activeLayer.children) {
          if (item.markRemarkId && item.markType !== 'point') {
            item.bounds.height *= scaleReverse
            item.bounds.width *= scaleReverse
            if (item.textObject) item.textObject.fontSize *= scaleReverse
            continue
          }
          if (!item instanceof Paper.PointText) continue
          if (!item.fontSize) continue
          item.fontSize *= scaleReverse
        }
        view.scale(scale, projectPos)
      } catch (e) {
        console.log('editorZoom', e)
      }
      event.preventDefault()
    },

    handlerMouseDrag(event) {
      if (event.event.buttons !== 2) return
      const { view, dragStart } = this
      view.element.style.cursor = Cursor.Move
      const offsetX = event.event.offsetX,
        offsetY = event.event.offsetY
      if (!dragStart) {
        this.dragStart = { x: offsetX, y: offsetY }
        return
      }
      const delta = new Paper.Point(offsetX - dragStart.x, offsetY - dragStart.y).divide(view.zoom)
      view.translate(delta)
      dragStart.x = offsetX
      dragStart.y = offsetY
    },
    handlerMouseUp(event) {
      document.body.style.cursor = Cursor.Auto
      this.dragStart = null
    },
    handlerMouseDown(event) {},

    handleAnnotationChange(annotation) {
      this.mImageMarker.$emit('update', annotation)
    },
    handleSelectedChange(selected) {
      console.log(selected)
      this.mImageMarker.$emit('selected-change', selected)
    },

    draw(imageData) {
      const { raster, imageElement, project } = this
      this.loaded = false
      project.clear()
      const { blob, filename, mQaResultId } = imageData
      project.fileName = filename
      project.mQaResultId = mQaResultId
      imageElement.src = blob
      console.log('reset paper image')
    },
    // 重置图片组件显示状态/图片缩放
    resizeCanvasWithImage() {
      const canvas = this.$refs.canvas
      const { offsetWidth: width, offsetHeight: height } = canvas
      const { imageSize: size, view } = this
      this.viewSize = { width, height }
      view.viewSize = new Paper.Size(width, height)
      if (!size) return

      const { iWidth, iHeight } = size
      const viewRatio = width * iHeight
      const bitmapRatio = iWidth * height
      const scaleFactor = viewRatio < bitmapRatio ? width / iWidth : height / iHeight
      view.scale(scaleFactor / view.zoom)
      view.center = new Paper.Point(iWidth * 0.5, iHeight * 0.5)
    },
    drawAnnotation() {},

    drwaReferLiens() {
      const { config, mainLayer, imageSize, attributesTextOpacity } = this
      const { referLines } = config
      const { iWidth, iHeight } = imageSize
      const fontSize = 24

      mainLayer.activate()
      referLines.forEach((referLine) => {
        let pt1, pt2
        if (referLine.direct === ReferDirect.VERTICAL) {
          const offsetX = iWidth * referLine.val
          pt1 = new Paper.Point(offsetX, 0)
          pt2 = new Paper.Point(offsetX, iHeight)
        } else {
          const offsetY = iHeight * referLine.val
          pt1 = new Paper.Point(0, offsetY)
          pt2 = new Paper.Point(iWidth, offsetY)
        }

        const descriptionText = new Paper.PointText({
          position: pt1,
          fillColor: referLine['color'],
          justification: 'left',
          fontSize: fontSize,
          locked: true,
          strokeWidth: 2,
          strokeScaling: false,
          content: referLine.desc,
          opacity: attributesTextOpacity,
        })
        const path = new Paper.Path({
          strokeColor: referLine['color'],
          strokeWidth: 1,
          strokeScaling: false,
          closed: false,
          opacity: 1,
          textObject: descriptionText,
          tag: referLine['desc'],
        })
        path.add(pt1, pt2)
      })
    },

    imageDispose() {
      window.removeEventListener('resize', this.resizeCanvasWithImage, false)

      const { project } = this
      project.clear()
      project.remove()

      this.mainLayer = null
      this.rasterLayer = null
      this.raster = null
      this.project = null
      this.imageElement.onload = null
      this.imageElement = null
      this.view = null
    },
  },
  beforeDestroy() {
    this.imageDispose()
  },
  watch: {
    file: {
      immediate: false,
      handler(imagedata) {
        if (!imagedata) return
        this.draw(imagedata)
      },
    },
  },
}
</script>

<style lang="scss" scoped>
.container-wrapper {
  border-radius: 4px;
  border: 1px solid #e6ebf5;
  background-color: #fff;
  overflow: hidden;
  color: #303133;
  transition: 0.3s;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  padding: 0;

  canvas[resize] {
    width: 100%;
    height: 100%;
  }
}
</style>
